msg_tool\scripts\hexen_haus\img/
png.rs

1//! HexenHaus PNG Image
2use crate::ext::io::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::img::*;
6use anyhow::Result;
7use std::io::{Read, Seek, SeekFrom};
8
9#[derive(Debug)]
10/// HexenHaus PNG Image Builder
11pub struct PngImageBuilder {}
12
13impl PngImageBuilder {
14    /// Creates a new instance of `PngImageBuilder`
15    pub fn new() -> Self {
16        PngImageBuilder {}
17    }
18}
19
20impl ScriptBuilder for PngImageBuilder {
21    fn default_encoding(&self) -> Encoding {
22        Encoding::Cp932
23    }
24
25    fn build_script(
26        &self,
27        data: Vec<u8>,
28        _filename: &str,
29        _encoding: Encoding,
30        _archive_encoding: Encoding,
31        config: &ExtraConfig,
32        _archive: Option<&Box<dyn Script>>,
33    ) -> Result<Box<dyn Script>> {
34        Ok(Box::new(PngImage::new(MemReader::new(data), config)?))
35    }
36
37    fn extensions(&self) -> &'static [&'static str] {
38        &["png"]
39    }
40
41    fn script_type(&self) -> &'static ScriptType {
42        &ScriptType::HexenHausPng
43    }
44
45    fn is_image(&self) -> bool {
46        true
47    }
48
49    fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
50        if buf_len >= 4 && buf.starts_with(b"IMGD") {
51            return Some(10);
52        }
53        None
54    }
55}
56
57#[derive(Debug)]
58/// Extra information for PNG image
59pub struct ExtraInfo {
60    /// x offset
61    pub offset_x: u32,
62    /// y offset
63    pub offset_y: u32,
64}
65
66#[derive(Debug)]
67pub struct PngImage {
68    reader: MemReader,
69    extra: Option<ExtraInfo>,
70}
71
72impl PngImage {
73    /// Creates a new instance of `PngImage`
74    pub fn new(mut reader: MemReader, _config: &ExtraConfig) -> Result<Self> {
75        let mut header = [0; 4];
76        reader.read_exact(&mut header)?;
77        if &header != b"IMGD" {
78            return Err(anyhow::anyhow!("Not a valid HexenHaus PNG image"));
79        }
80        reader.seek(SeekFrom::End(-14))?;
81        let cnt = reader.read_exact_vec(12)?;
82        let extra = if cnt.starts_with(b"CNTR") {
83            let mut cnt_reader = MemReaderRef::new(&cnt[4..]);
84            let offset_x = cnt_reader.read_u32()?;
85            let offset_y = cnt_reader.read_u32()?;
86            Some(ExtraInfo { offset_x, offset_y })
87        } else {
88            None
89        };
90        Ok(PngImage { reader, extra })
91    }
92}
93
94impl Script for PngImage {
95    fn default_output_script_type(&self) -> OutputScriptType {
96        OutputScriptType::Json
97    }
98
99    fn default_format_type(&self) -> FormatOptions {
100        FormatOptions::None
101    }
102
103    fn is_image(&self) -> bool {
104        true
105    }
106
107    fn export_image(&self) -> Result<ImageData> {
108        let mut reader = self.reader.to_ref();
109        reader.pos = 0;
110        let reader = StreamRegion::with_start_pos(reader, 0x10)?;
111        let img = load_png(reader)?;
112        Ok(img)
113    }
114
115    fn extra_info<'a>(&'a self) -> Option<Box<dyn AnyDebug + 'a>> {
116        self.extra
117            .as_ref()
118            .map(|e| Box::new(e) as Box<dyn AnyDebug>)
119    }
120}